package com.md.api.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 处理下面字符串的比较，保证转换后的数字在数据库中顺序如下
 * A  > BBB+ >BBB- > BB > B++ >B+ > B > B- >B-- >B--- > C
 * 将AAA,BB,B+转换为占6位的2进制数，规则如下
 * 数据位 (3) + 数据个数（3） + 符号位（2） +符号位个数（3）
 * <p>
 * 数据位 (2)：
 * A: 5
 * B：4
 * C: 3
 * D：2
 * E:1
 * F:0
 * 数据个数（3）：
 * 1:01
 * 2:10
 * 3:11
 * 。。。
 * 符号位：（2） +/-
 * 00: -
 * 01：无符号
 * 10: +
 * 符号位个数：（3）
 * 符号为-时，取3-符号位个数,因为负号越多，越小
 *
 * @author liaojia
 * @date 2020-09-17
 */
public class CreditEvaluateLevelUtil {

    private static Logger logger = LoggerFactory.getLogger(CreditEvaluateLevelUtil.class);

    enum SignMapping {
        A_SIGN('A', (byte) 5, true),
        B_SIGN('B', (byte) 4, true),
        C_SIGN('C', (byte) 3, true),
        D_SIGN('D', (byte) 2, true),
        E_SIGN('E', (byte) 1, true),
        F_SIGN('F', (byte) 0, true),
        ADD_SIGN('+', (byte) 2, false),
        DER_SIGN('-', (byte) 0, false),
        NONE_SIGN(' ', (byte) 1, false);
        private char sign;
        private byte binNum;
        private boolean ifLetter;

        private SignMapping(char sign, byte binNum, boolean ifLetter) {
            this.sign = sign;
            this.binNum = binNum;
            this.ifLetter = ifLetter;
        }

        public byte getBinNum() {
            return binNum;
        }

        public static SignMapping getSignMappingBySign(char sign) {
            SignMapping[] values = SignMapping.values();
            for (SignMapping signMapping : values) {
                if (signMapping.sign == sign) {
                    return signMapping;
                }
            }

            return null;
        }

        public static SignMapping getSignMappingByBinNum(Integer binNum, boolean ifLetter) {
            SignMapping[] values = SignMapping.values();
            for (SignMapping signMapping : values) {
                if (signMapping.binNum == binNum && signMapping.ifLetter == ifLetter) {
                    return signMapping;
                }
            }
            return null;
        }
    }

    private static final Pattern EVALUATE_LEVEL_PATTERN = Pattern.compile("(A{1,5}|B{1,5}|C{1,5}|D{1,5}|E{1,5}|F{1,5})(\\+{0,3}|-{0,3})");
    private static final Pattern SIGN_PATTERN = Pattern.compile("[+|-]");

    /**
     * 将信用等级转换为具体数字，以便排序
     *
     * @param evaluateLevel
     * @return
     */
    public static Integer convertToLevelNum(String evaluateLevel) {
        if (evaluateLevel == null) {
            return null;
        }
        if (!EVALUATE_LEVEL_PATTERN.matcher(evaluateLevel).matches()) {
            logger.warn("input evaluate level string pattern error!");
            return null;
        }
        SignMapping letterSignMapping = SignMapping.getSignMappingBySign(evaluateLevel.charAt(0));
        int letterCharLen = evaluateLevel.length();

        SignMapping tailSignMapping = SignMapping.NONE_SIGN;
        Matcher matcher = SIGN_PATTERN.matcher(evaluateLevel);
        int signCharLen = 0;

        if (matcher.find()) {
            int signIndex = matcher.start();
            //判断是+/-
            tailSignMapping = SignMapping.getSignMappingBySign(evaluateLevel.charAt(signIndex));
            //符号有多少位
            signCharLen = evaluateLevel.length() - signIndex;
            //符合是第几位
            letterCharLen = signIndex;
        }
        //先转化成二进制进行或运算  计算之后在转成十进制
        return letterSignMapping.binNum << 8 | letterCharLen << 5 | tailSignMapping.binNum << 3 | (tailSignMapping == SignMapping.DER_SIGN ? (7 - signCharLen) : signCharLen);
    }

    /**
     * 将排序数字转换为具体的信用等级字符串
     *
     * @param convertToLevelNum
     * @return
     */
    public static String convertToEvaluateLevel(Integer convertToLevelNum) {

        if (convertToLevelNum == null || convertToLevelNum >> 11 != 0) {
            logger.warn("input level number exists error!");
            return null;
        }

        SignMapping letterSignMapping = SignMapping.getSignMappingByBinNum(convertToLevelNum >> 8, true);

        int letterCharLen = (convertToLevelNum >> 5) & 7;
        if (letterSignMapping == null || letterCharLen == 0) {
            return null;
        }
        SignMapping signCharMapping = SignMapping.getSignMappingByBinNum(convertToLevelNum >> 3 & 3, false);
        int signCharLen = SignMapping.DER_SIGN != signCharMapping ? convertToLevelNum & 7 : (7 - convertToLevelNum & 7);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < letterCharLen; i++) {
            sb.append(letterSignMapping.sign);
        }
        for (int i = 0; i < signCharLen; i++) {
            sb.append(signCharMapping.sign);
        }
        return sb.toString();
    }

    /**
     * 测试部分，生成所有可能的信用等级字符
     */
    static class CharEntity {
        /**
         * 信用等级字符
         */
        String str;
        /**
         * 转换后对应的2进制
         */
        String binStr;
        /**
         * 转换后的十进制
         */
        Integer num;

        @Override
        public String toString() {
            return "|" + formatStr(str) + formatStr(binStr) + formatStr(num.toString());
        }

        public static void main(String[] args) {
            System.out.println(
                    convertToLevelNum("AA")
            );

//            String s = convertToEvaluateLevel(2000);
//            List<CharEntity> list = new LinkedList<>();
//            generaCreditEvaluateStr(list, 'A');
//            generaCreditEvaluateStr(list, 'B');
//            generaCreditEvaluateStr(list, 'C');
//            generaCreditEvaluateStr(list, 'D');
//            generaCreditEvaluateStr(list, 'E');
//            generaCreditEvaluateStr(list, 'F');
//
//            System.out.println(formatStrF("|信用等级字符") + formatStrF("转换后对应的2进制") + formatStrF("转换后的十进制") + formatStrF("十进制数转换为信用等级字符"));
//            list.stream().sorted(Comparator.comparing(o -> o.num)).forEach(e -> System.out.println(e.toString() + formatStr(convertToEvaluateLevel(e.num))));

        }

        private static String formatStrF(String s) {
            //左对齐
            return String.format("%-16s|", s);
        }

        private static String formatStr(String s) {
            //左对齐
            return String.format("%-20s|", s);
        }

        private static void generaCreditEvaluateStr(List<CharEntity> list, char a) {
            for (int i = 0; i < 5; i++) {
                String s = generateChar(a, i + 1);

                CharEntity entity0 = new CharEntity();
                entity0.str = s;
                entity0.num = convertToLevelNum(entity0.str);
                entity0.binStr = Integer.toBinaryString(entity0.num);
                list.add(entity0);
                for (int j = 1; j < 3; j++) {
                    CharEntity entity = new CharEntity();
                    entity.str = s + generateChar('+', j);
                    entity.num = convertToLevelNum(entity.str);
                    entity.binStr = Integer.toBinaryString(entity.num);
                    list.add(entity);


                    CharEntity entity2 = new CharEntity();
                    entity2.str = s + generateChar('-', j);
                    entity2.num = convertToLevelNum(entity2.str);
                    entity2.binStr = Integer.toBinaryString(entity2.num);
                    list.add(entity2);

                }
            }
        }

        public static String generateChar(char c, int num) {
            StringBuilder s = new StringBuilder();
            for (int i = 0; i < num; i++) {
                s.append(c);
            }
            return s.toString();
        }
    }


}
